package com.pb.infra.oth.service;

import com.pb.infra.oth.entity.ParamUniqueTable;
import com.pb.infra.oth.mapper.ParamUniqueTableMapper;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

/**
 * 获取自增序号
 * @author liudebao
 */
@Service("UniqueTableService")
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Data
public class UniqueTableService {

    @Autowired
    private ParamUniqueTableMapper parameteUniqueTableMapper;

    /**
     * redis数据访问
     */
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 数据库当前存储序号最大值
     */
    private long maxId;

    private long currentId = 0L;

    /**
     * 缓存值
     */
    private long poolSize;

    /**
     * 序号类型
     */
    private String tabName;

    public UniqueTableService() {}

    public UniqueTableService(String paramString, long paramLong) {
        this.tabName = paramString;
        this.poolSize = paramLong;
    }

    /**
     * 获取下一个序号
     * @return
     */
    public long getNextId() {
        if (this.currentId > this.maxId || this.currentId < 1) {
            updateMaxId();
        }
        return (++this.currentId);
    }

    /**
     * 更新最大值
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE)
    public void updateMaxId() {
        long dbExistedCode = getDBExistedValue(this.tabName, true);//阈值
        boolean isResetCurrentId = false;
        long newValue = 0L;
        if (dbExistedCode > -1L) { // dbExistedCode 已存在值0 5
            if (dbExistedCode > this.maxId) {  //最大值小于阈值
                isResetCurrentId = true;
            }
            newValue = dbExistedCode + this.poolSize;
            update(this.tabName, newValue);
        } else {
            newValue = this.poolSize;
            insert(this.tabName, newValue);
        }
        this.maxId = newValue;
        if (isResetCurrentId == true) {
            this.currentId = (this.maxId - this.poolSize);
        }
    }

    /**
     * 数据库当前存储最大值
     * @param seqName
     * @param update
     * @return
     */
    private long getDBExistedValue(String seqName, boolean update) {
        long num = getDBExistedValue(seqName);
        if (num < 0) {
            return -1;
        }
        return num;
    }

    private long getDBExistedValue(String seqName) {


        ParamUniqueTable parameteUniqueTable = parameteUniqueTableMapper.selectByPrimaryKey(seqName);
        if (parameteUniqueTable == null) {
            return -1L;
        } else {
            if (!redisTemplate.hasKey(seqName)) {
                redisTemplate.opsForValue().set(seqName, parameteUniqueTable.getCode().toPlainString(), 24L, TimeUnit.HOURS);
                return Long.valueOf(parameteUniqueTable.getCode().toPlainString()) + this.poolSize;
            } else {
                return Long.valueOf(parameteUniqueTable.getCode().toPlainString());
            }
        }
    }
    /**
     * 修改阈值
     * @param seqName
     * @param value
     */
    private void update(String seqName, long value) {
        ParamUniqueTable parameteUniqueTable = new ParamUniqueTable();
        parameteUniqueTable.setCode(new BigDecimal(value));
        parameteUniqueTable.setSeqName(seqName);
        parameteUniqueTableMapper.updateByPrimaryKey(parameteUniqueTable);
    }

    /**
     * 新增阈值
     * @param seqName
     * @param value
     */
    private void insert(String seqName, long value) {
        ParamUniqueTable parameteUniqueTable = new ParamUniqueTable();
        parameteUniqueTable.setCode(new BigDecimal(value));
        parameteUniqueTable.setSeqName(seqName);
        parameteUniqueTableMapper.insertSelective(parameteUniqueTable);
    }

    /**
     * 删除序号类型
     * @param seqName
     */
    private void delete(String seqName) {
        parameteUniqueTableMapper.deleteByPrimaryKey(seqName);
    }

}
